#define M_CROP     0
#define M_FIT_X    1
#define M_FIT_Y    2
#define M_COVER    3
#define M_CONTAINS 4

uniform mat4 u_MVP;
uniform vec4 u_crop;
uniform float u_mirror_y;
uniform float u_src_aspect;
uniform float u_dst_aspect;
uniform int u_mode;

attribute vec4 a_position;
attribute vec2 a_texcoord0;

varying vec2 v_uv;


vec2 fitX (float src_aspect, float dst_aspect, vec2 uv) {
    float s = src_aspect / dst_aspect;
    float v = (uv.y - 0.5) * s + 0.5;
    return vec2(uv.x, v);
}

vec2 fitY (float src_aspect, float dst_aspect, vec2 uv) {
    float s = dst_aspect / src_aspect;
    float u = (uv.x - 0.5) * s + 0.5;
    return vec2(u, uv.y);
}

vec2 cover (float src_aspect, float dst_aspect, vec2 uv) {
    vec2 sd = vec2(src_aspect, dst_aspect);
    vec2 ds = sd.yx;
    vec2 s = ds / sd;
    vec2 p = (uv - 0.5) * s + 0.5;
    vec2 a = step(ds, sd);
    return mix(uv, p, a);
}

vec2 contains (float src_aspect, float dst_aspect, vec2 uv) {
    vec2 sd = vec2(src_aspect, dst_aspect);
    vec2 ds = sd.yx;
    vec2 s = ds / sd;
    vec2 p = (uv - 0.5) * s + 0.5;
    vec2 a = step(sd, ds);
    return mix(uv, p, a);
}

vec2 crop (vec4 rect, vec2 uv) {
    return mix(rect.xy, rect.zw, uv);
}

float clamp_to_border (vec2 uv) {
    uv = step(vec2(0.0), uv) * step(uv, vec2(1.0));
    return uv.x * uv.y;
}

void main () {
    vec2 uv = vec2(a_texcoord0.x, mix(a_texcoord0.y, 1.0 - a_texcoord0.y, u_mirror_y));
    if (u_mode == M_FIT_X) {
        v_uv = fitX(u_src_aspect, u_dst_aspect, uv);
    } else if (u_mode == M_FIT_Y) {
        v_uv = fitY(u_src_aspect, u_dst_aspect, uv);
    } else if (u_mode == M_COVER) {
        v_uv = cover(u_src_aspect, u_dst_aspect, uv);
    } else if (u_mode == M_CONTAINS) {
        v_uv = contains(u_src_aspect, u_dst_aspect, uv);
    } else {
        v_uv = crop(u_crop, uv);
    }
    gl_Position = u_MVP * a_position;
}
